package org.carabiner.infopanel;

import java.awt.BasicStroke;
import java.awt.Component;
import java.awt.Frame;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.Timer;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;

/**
 * A listener that will draw a highlighted border around a trees selection.
 * ComponentWarningTreeListener draws a rectangle into the graphics context of
 * the control currently selected in the {@link javax.swing.JTree} the listener
 * is listeneing to.
 * 
 * <p>
 * Carabiner Testing Framework
 * </p>
 * <p>
 * Copyright: <a href="http://www.gnu.org/licenses/gpl.html">GNU Public License</a>
 * </p>
 * 
 * @author John Januskey (john.januskey@gmail.com)
 * 
 */
class ComponentWarningTreeSelectionListener implements TreeSelectionListener,
    ActionListener
{
  private Component baseComponent;

  private CarabinerComponentNode selectedNode;

  private Timer highlightTimer;

  /**
   * Initializes a new instance of the
   * <code>ComponentWarningTreeSelectionListener</code> class.
   * 
   * @param component
   *          Component
   */
  public ComponentWarningTreeSelectionListener(Component component)
  {
    baseComponent = component;
    // Create a time to draw a border around the component currently selected
    // in the tree this selection listener is listening to.
    highlightTimer = new javax.swing.Timer(500, this);
  }

  /**
   * Called whenever the value of the selection changes.
   * 
   * @param e
   *          the event that characterizes the change.
   */
  public void valueChanged(TreeSelectionEvent e)
  {
    // stop the highlight timer to update internal state.
    highlightTimer.stop();
    // if there is a valid component to highlight and it has a highlight color,
    // update the selectedNode and restart the timer.
    if (e.getNewLeadSelectionPath() != null)
    {
      selectedNode = (CarabinerComponentNode) e.getNewLeadSelectionPath()
          .getLastPathComponent();
      if (selectedNode.getHighlightColor() != null)
      {
        highlightTimer.start();
      }
    }
    baseComponent.repaint();
  }

  // Package level accessors for testing.
  Component getBaseComponent()
  {
    return baseComponent;
  }

  CarabinerComponentNode getSelectedNode()
  {
    return selectedNode;
  }

  boolean isTimerRunning()
  {
    return highlightTimer.isRunning();
  }

  boolean isRepaintTrue()
  {
    return repaint;
  }

  private boolean repaint = true;

  public void actionPerformed(ActionEvent e)
  {
    if (selectedNode != null)
    {
      Component selectedComponent = selectedNode.getComponent();

      Component firstNonZero = getFirstNonZeroComponent(selectedComponent);
      if (repaint)
      {
        if (firstNonZero instanceof Frame)
        {
          ((Frame) selectedComponent).setVisible(true);
        } else
        {
          if (selectedComponent.isVisible())
          {
            firstNonZero.repaint();
          } else
          {
            baseComponent.repaint();
          }
        }
      } else
      {
        boolean emptyControl = false;
        Rectangle rect = selectedComponent.getBounds();
        if (rect.width == 0 || rect.height == 0)
        {
          rect = new Rectangle(selectedComponent.getX(), selectedComponent
              .getY(), 5, 5);
          emptyControl = true;
        }
        if (selectedComponent.getGraphics() != null)
        {
          Graphics2D g = (Graphics2D) selectedComponent.getGraphics().create();
          if (emptyControl)
          {
            g = (Graphics2D) firstNonZero.getGraphics().create();
            g.setColor(selectedNode.getHighlightColor());
            g.drawLine(rect.x, rect.y, rect.x + rect.width, rect.y
                + rect.height);
            g.drawLine(rect.x, rect.y + rect.height, rect.x + rect.width,
                rect.y);
            g.drawRect(rect.x, rect.y, rect.width, rect.height);
          } else
          {
            g.setStroke(new BasicStroke(3));
            g.setColor(selectedNode.getHighlightColor());
            g.drawRect(0, 0, rect.width - 1, rect.height - 1);
          }
        }
      }
    }
    repaint = !repaint;
  }

  /**
   * getFirstNonZeroComponent
   * 
   * @param selectedComponent
   *          Component
   * @return Component
   */
  private Component getFirstNonZeroComponent(Component selectedComponent)
  {
    if ((selectedComponent.getWidth() == 0 || selectedComponent.getHeight() == 0)
        && selectedComponent.getParent() != null)
    {
      return (getFirstNonZeroComponent(selectedComponent.getParent()));
    }
    return selectedComponent;
  }
}
